//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <elastos.h>
#include <elacfg.h>
#include "prxstub.h"
#include <aura.h>

#ifdef _GNUC
#define DECL_SYS_PROXY_ENTRY()             \
    __asm__(                               \
        ".text;"                           \
        ".align 4;"                        \
        ".globl _ProxyEntryFunc;"          \
        "_ProxyEntryFunc:"                 \
        ".intel_syntax;"                   \
        "push   esp;"                      \
        "mov    eax, dword ptr [esp + 8];" \
        "call   dword ptr [eax + 4];"      \
        "ret    0x4;"                      \
        ".att_syntax;"                     \
    )
#else
#define DECL_SYS_PROXY_ENTRY()              \
    __declspec( naked ) void ProxyEntryFunc()                   \
    {                                       \
        __asm push esp                      \
        __asm mov eax, dword ptr [esp + 8]  \
        __asm call dword ptr [eax +4]       \
        __asm ret  0x4                      \
    }
#endif

EXTERN_C void ProxyEntryFunc(void);
DECL_SYS_PROXY_ENTRY();

#define SYS_PROXY_RET_OFFSET    9
Address s_proxyEntryAddress;

#define PAGE_SIZE (1u << 12)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define PAGE_ALIGN(va) (((va)+PAGE_SIZE-1)&PAGE_MASK)

//EXTERN CriticalSection channelPoolCs;
PVoid channelPoolCs = NULL;

EXTERN_C ECode InitProxyEntry(void)
{
    ECode ec     = NOERROR;
    Address addr;

    ec = AuraVirtualMap(NULL,
                        PAGE_ALIGN(PROXY_ENTRY_NUM * PROXY_ENTRY_SIZE),
                        MemoryMap_Private,
                        MemoryProtection_RW,
                        &addr);
    if (FAILED(ec)) {
        s_proxyEntryAddress = (Address)NULL;
        return ec;
    }
   /* ec = _CVirtualMemory_Commit(addr);
    if (FAILED(ec)) {
        _CVirtualMemory_Free(addr,PROXY_ENTRY_NUM * PROXY_ENTRY_SIZE);
        return ec;
    }*/
//    Aura_printf("addr = 0x%x\n",addr);

    s_proxyEntryAddress = (Address)addr;
    Address *paddr = (Address*)addr;
    for (UInt32 n = 0; n < PROXY_ENTRY_NUM; n++) {
        //Aura_printf(" count(n) = 0x%x\n",n);
        memcpy(paddr, (void*)&ProxyEntryFunc, PROXY_ENTRY_SIZE);
        *(Int16*)&(paddr[SYS_PROXY_RET_OFFSET]) = ( (n + 1) << 2);
     //   *(Int16*)(&(((void*)addr)[SYS_PROXY_RET_OFFSET])) =
     //           ((n + 1) << 2); //??
        paddr += PROXY_ENTRY_SIZE  / sizeof(Address);
       // paddr = (char*)paddr + PROXY_ENTRY_SIZE;
    }

    ec = AuraVirtualProtect(s_proxyEntryAddress,
                            PAGE_ALIGN(PROXY_ENTRY_NUM * PROXY_ENTRY_SIZE),
                            MemoryProtection_RX);
    if (FAILED(ec)) {
        AuraVirtualUnmap(s_proxyEntryAddress,
                         PAGE_ALIGN(PROXY_ENTRY_NUM * PROXY_ENTRY_SIZE));
        return ec;
    }
    return AuraCriticalSectionCreate(&channelPoolCs);
}

EXTERN_C void DestroyProxyEntry(void)
{
    if (NULL != s_proxyEntryAddress) {
        AuraVirtualUnmap(s_proxyEntryAddress,
                        PAGE_ALIGN(PROXY_ENTRY_NUM * PROXY_ENTRY_SIZE));
        s_proxyEntryAddress = (Address)NULL;
    }
    releaseChannelPool();
    AuraCriticalSectionDestroy(channelPoolCs);
    return ;
}
